package org.zachary.imitation.raft.rpc;

import com.google.protobuf.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zachary.imitation.raft.Closure;
import org.zachary.imitation.raft.Status;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 * 收到请求之后的回调方法会封装到这个对象中。如果当前节点收到的是心跳消息，或者是投票的请求消息，这些请求处理起来很简单，那么直接返回响应即可。
 * 但是如果处理的是日志复制消息，收到领导者发送过来的日志复制的请求，处理这个请求的时候，需要等到日志复制成功才能回复响应。
 * 所以，在 JRaft 框架中，为某些请求定义了回调方法，当请求处理完毕后，再回调这个请求的回调方法，在回调方法中把处理好请求后的响应回复给目标节点，这个回调方法中就定义了发送响应的方法
 */
public class RpcRequestClosure implements Closure {
	private static final Logger logger = LoggerFactory.getLogger(RpcRequestClosure.class);
	private static final AtomicIntegerFieldUpdater<RpcRequestClosure> STATE_UPDATER = AtomicIntegerFieldUpdater.newUpdater(RpcRequestClosure.class, "state");

	private static final int                                          PENDING       = 0;
	private static final int                                          RESPOND       = 1;

	private final RpcContext                                          rpcCtx;
	private final Message defaultResp;

	private volatile int                                              state         = PENDING;

	public RpcRequestClosure(RpcContext rpcCtx) {
		this(rpcCtx, null);
	}

	public RpcRequestClosure(RpcContext rpcCtx, Message defaultResp) {
		super();
		this.rpcCtx = rpcCtx;
		this.defaultResp = defaultResp;
	}

	public RpcContext getRpcCtx() {
		return rpcCtx;
	}

	public void sendResponse(final Message msg) {
		if (!STATE_UPDATER.compareAndSet(this, PENDING, RESPOND)) {
			logger.warn("A response: {} sent repeatedly!", msg);
			return;
		}
		this.rpcCtx.sendResponse(msg);
	}

	@Override
	public void run(final Status status) {
		// sendResponse(RpcFactoryHelper.responseFactory().newResponse(this.defaultResp, status));
	}
}
